package conf_service

import (
	"encoding/json"
	"fmt"
	"peilian-api/app/global/common"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/errors"
	"peilian-api/app/global/variable"
	"peilian-api/app/model"
	"peilian-api/utils/tools"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

type ConstituteService struct{}

func (cs *ConstituteService) AddConstitute(ctx *gin.Context, car model.ConstituteAddRes) *errors.ErrRes {
	belongToId := car.BelongToId
	name := car.Name
	typ := car.Type
	// 1. 先根据查询该信息是否存在
	var consObj = new(tables.Constitute)
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["belong_to_id"] = belongToId
	whereMap["name"] = name
	whereMap["type"] = typ
	c, err := consObj.GetInfoByWhere(whereMap)
	if err != nil || c.ID != 0 {
		return errors.NewErrInfo(10001, fmt.Errorf("该信息已经存在,无需添加"))
	}
	// 2. 信息不存在，则插入
	if err := consObj.InsertInfoMap(whereMap); err != nil {
		return errors.NewErrInfo(10001, fmt.Errorf("数据库操作失败"))
	}
	// 3. 根据条件获取agent_id
	agentId, schoolId, err := new(tables.Constitute).GetIdsById(int64(belongToId))
	// 查询数据
	if err != nil {
		return errors.NewErrInfo(10001, fmt.Errorf("数据添加失败"))
	}
	ci, _ := new(tables.Constitute).GetAllInfoTree(uint(schoolId))
	// 4. 更新缓存
	b, _ := json.Marshal(ci)
	variable.DB.Redis.Set(fmt.Sprintf(common.RedisConsituteIdsKey, agentId), string(b), -1)
	return nil
}

func (cs *ConstituteService) UpdateConstitute(ctx *gin.Context, cur model.ConstituteUpdateRes) *errors.ErrRes {
	id := cur.Id
	name := cur.Name
	typ := cur.Type
	var consObj = new(tables.Constitute)
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["id"] = id
	// 1. 先获取belongToId
	c, err := consObj.GetInfoByWhere(whereMap)
	if err != nil {
		return errors.NewErrInfo(10001, fmt.Errorf("数据库操作错误"))
	}
	if c.ID == 0 {
		return errors.NewErrInfo(10002, fmt.Errorf("该数据不存在"))
	}
	// 2. 先根据查询修改的信息是否存在
	whereMap = make(map[string]interface{}, 0)
	whereMap["belong_to_id"] = c.BelongToID
	whereMap["name"] = name
	whereMap["type"] = typ
	c, err = consObj.GetInfoByWhere(whereMap)
	if err != nil || c.ID != 0 {
		return errors.NewErrInfo(10003, fmt.Errorf("该信息已经存在,请重新修改名称"))
	}
	// 3. 信息不存在，则更新
	whereMap = make(map[string]interface{}, 0)
	whereMap["name"] = name
	if err := consObj.UpdateInfoByWhereStr(whereMap, "id = "+strconv.Itoa(int(id))); err != nil {
		return errors.NewErrInfo(10004, fmt.Errorf("数据库操作失败"))
	}
	// 4. 寻找需要更新的constitute_id
	var ids []string
	if typ == tables.AcademyType {
		// 查询该学院下面的所有的职业
		whereMap = make(map[string]interface{}, 0)
		whereMap["belong_to_id"] = id
		ci, _ := consObj.GetConstituteByBelongToId(int(id))
		if len(ci) != 0 {
			for _, v := range ci {
				ids = append(ids, strconv.Itoa(int(v.Id)))
			}
		}
		ids = append(ids, strconv.Itoa(int(id)))
		// 更新user表
		if _, err := new(tables.User).UpdateUserInfoByWhereStr(map[string]interface{}{"academy": name}, fmt.Sprintf("constitute_id in (%s)", strings.Trim(tools.ArraysToStr(ids, ","), ","))); err != nil {
			return errors.NewErrInfo(10006, fmt.Errorf("数据库操作失败"))
		}
	} else if typ == tables.ProfessionType {
		ids = append(ids, strconv.Itoa(int(id)))
		// 更新user表
		if _, err := new(tables.User).UpdateUserInfoByWhereStr(map[string]interface{}{"profession": name}, fmt.Sprintf("constitute_id in (%s)", strings.Trim(tools.ArraysToStr(ids, ","), ","))); err != nil {
			return errors.NewErrInfo(10006, fmt.Errorf("数据库操作失败"))
		}
	} else {
		return errors.NewErrInfo(10005, fmt.Errorf("您无权限更新该数据"))
	}

	// 5. 根据条件获取agent_id
	agentId, schoolId, err := new(tables.Constitute).GetIdsById(int64(id))
	if err != nil {
		return errors.NewErrInfo(10001, fmt.Errorf("数据添加失败"))
	}
	ci, _ := new(tables.Constitute).GetAllInfoTree(uint(schoolId))
	// 6. 更新缓存
	b, _ := json.Marshal(ci)
	variable.DB.Redis.Set(fmt.Sprintf(common.RedisConsituteIdsKey, agentId), string(b), -1)

	return nil
}

// 删除操作
func (cs *ConstituteService) DeleteConstitute(ctx *gin.Context, id uint) *errors.ErrRes {
	var consObj = new(tables.Constitute)
	var whereMap map[string]interface{}
	whereMap = make(map[string]interface{}, 0)
	whereMap["id"] = id
	// 1. 先获取belongToId
	c, err := consObj.GetInfoByWhere(whereMap)
	if err != nil {
		return errors.NewErrInfo(10001, fmt.Errorf("数据库操作错误"))
	}
	if c.ID == 0 {
		return errors.NewErrInfo(10002, fmt.Errorf("该数据不存在"))
	}
	typ := c.Type

	// 2. 寻找要删除的id
	var ids []string
	if typ == tables.AcademyType {
		whereMap = make(map[string]interface{}, 0)
		whereMap["belong_to_id"] = id
		ci, _ := consObj.GetConstituteByBelongToId(int(id))
		if len(ci) != 0 {
			for _, v := range ci {
				ids = append(ids, strconv.Itoa(int(v.Id)))
			}
		}
		ids = append(ids, strconv.Itoa(int(id)))
	} else if typ == tables.ProfessionType {
		ids = append(ids, strconv.Itoa(int(id)))
	} else {
		return errors.NewErrInfo(10003, fmt.Errorf("您无权限更新该数据"))
	}
	// 3. 查询该数据是否被学生占用
	userList, err := new(tables.User).GetUsersByWhereStr(fmt.Sprintf("constitute_id in (%s)", strings.Trim(tools.ArraysToStr(ids, ","), ",")), "id")
	if err != nil {
		return errors.NewErrInfo(10004, fmt.Errorf("数据库操作失败"))
	}
	if len(userList) != 0 {
		return errors.NewErrInfo(10005, fmt.Errorf("请将机构内全部学生移除后在进行删除"))
	}
	// 4. 删除数据
	if err := consObj.DeleteInfoByWhere(fmt.Sprintf("id in (%s)", strings.Trim(tools.ArraysToStr(ids, ","), ","))); err != nil {
		return errors.NewErrInfo(10006, fmt.Errorf("数据库操作失败"))
	}
	// 5. 根据条件获取agent_id
	agentId, schoolId, err := new(tables.Constitute).GetIdsById(int64(*c.BelongToID))
	if err != nil {
		return errors.NewErrInfo(10001, fmt.Errorf("数据添加失败"))
	}
	ci, _ := new(tables.Constitute).GetAllInfoTree(uint(schoolId))
	// 6. 更新缓存
	b, _ := json.Marshal(ci)
	variable.DB.Redis.Set(fmt.Sprintf(common.RedisConsituteIdsKey, agentId), string(b), -1)
	return nil
}

// 获取组织账号名称
func (cs *ConstituteService) GetOrganizeConfig(ctx *gin.Context) ([]model.CfgInfos, *errors.ErrRes) {
	var out []model.CfgInfos
	// 1. 先判断该用户是否是超级账户
	uid, exists := ctx.Get("uid")
	if !exists {
		return out, errors.NewErrInfo(errors.SessionUidErrorCode, fmt.Errorf("用户未登录"))
	}
	// 根据uid获取user信息
	us, _ := tables.GetAgentInfoByUid(uid.(uint))

	// 普通管理员
	if us.Type == tables.UserTypeAdmin {
		constituteId := us.ConstituteID
		out, _ = new(tables.Constitute).GetAllInfoBySchoolId(int(constituteId))
	} else if us.Type == tables.UserTypeSadmin { // 超管
		// 首先去查询redis
		// sc := variable.DB.Redis.Get(common.RedisConsituteSadminKey)
		// str, err := sc.Result()
		// if len(str) == 0 || sc.Err() != nil || err != nil {
		// 	new(ConstituteService).SetRedisConsituteSadminKey(false)
		// } else {
		// 	json.Unmarshal([]byte(str), &out)
		// }
		// out, _ = new(tables.Constitute).GetAllInfoTree(0)
		// 获取所有机构的信息
		agentList, _ := new(tables.Agent).GetAgentList()
		for i := 0; i < len(agentList); i++ {
			// agentIds = append(agentIds, fmt.Sprintf(common.RedisConsituteIdsKey, agentList[i].ID))
			sc := variable.DB.Redis.Get(fmt.Sprintf(common.RedisConsituteIdsKey, agentList[i].ID))
			scList, _ := sc.Result()
			var ts []model.CfgInfos
			if len(scList) != 0 {
				json.Unmarshal([]byte(scList), &ts)

			} else {
				// 查询学校
				var whereMap map[string]interface{}
				whereMap = make(map[string]interface{}, 0)
				whereMap["agent_id"] = agentList[i].ID
				c, _ := new(tables.Constitute).GetInfoByWhere(whereMap)
				var sc []model.CfgInfos
				sc = append(sc, model.CfgInfos{
					Id:    c.ID,
					Name:  c.Name,
					Type:  "school",
					Value: sc,
				})
				ts = append(ts, model.CfgInfos{
					Id:    agentList[i].ID,
					Name:  agentList[i].AgentName,
					Type:  "agent",
					Value: sc,
				})
			}
			out = append(out, ts...)
		}
	}
	return out, nil
}

// 设置侧边栏
func (cs *ConstituteService) SetRedisConsituteSadminKey(flag bool) ([]model.CfgInfos, *errors.ErrRes) {
	var count = 0
	if flag {
		for {
			sc := variable.DB.Redis.RPop(common.RedisQueueConstituteIds)
			s, err := sc.Result()
			if err == nil && len(s) != 0 {
				count++
				continue
			}
			break
		}
		if count == 0 {
			return []model.CfgInfos{}, nil
		}
	}
	out, _ := new(tables.Constitute).GetAllInfoTree(0)
	byteOut, _ := json.Marshal(out)

	// 可以忽略掉设置
	variable.DB.Redis.Set(common.RedisConsituteSadminKey, string(byteOut), 12*time.Hour)
	return out, nil
}

// 设置侧边栏
func (cs *ConstituteService) SetRedisConsituteKey() {
	// 1. 查询所有的学校
	cons, _ := new(tables.Constitute).GetConstituteByType("school")
	for i := 0; i < len(cons); i++ {
		ci, _ := new(tables.Constitute).GetAllInfoTree(uint(cons[i].Id))
		// 2. 更新缓存
		b, _ := json.Marshal(ci)
		variable.DB.Redis.Set(fmt.Sprintf(common.RedisConsituteIdsKey, cons[i].AgentId), string(b), -1)
	}
}
